/*  This file is part of -_-.

    -_- is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    -_- is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with -_-.  If not, see <http://www.gnu.org/licenses/>.

    Copyright 2012-2013 Oliver Katz */

#include "share.h"
#include "../common/debug.h"

z_share_server z_share_server_init(z_ipc_server *ipc, z_size n)
{
	z_share_server tmp;
	
	tmp.ptrs = (z_data **)malloc(sizeof(z_data *)*n);
	memset(tmp.ptrs, 0, sizeof(z_data *)*n);

	tmp.wp = (int *)malloc(sizeof(int)*n);
	memset(tmp.wp, 0, sizeof(int)*n);

	tmp.nptrs = n;

	tmp.srv = ipc;

	return tmp;
}

int z_share_server_release(z_share_server s)
{
	printf("0x%08x 0x%08x\n", (int)s.ptrs, (int)s.wp);
	if (s.ptrs != NULL)
		free(s.ptrs);
	if (s.wp != NULL)
		free(s.wp);
	return 0;
}

z_data *z_share_server_bind_rw(z_share_server *s, z_size idx, z_data *d)
{
	if (idx >= s->nptrs)
	{
		Z_WARNING("share overflow (%i >= %i)", idx, s->nptrs);
		return NULL;
	}

	s->ptrs[idx] = d;
	s->wp[idx] = Z_SHARE_RW;
	return d;
}

z_data *z_share_server_bind_ro(z_share_server *s, z_size idx, z_data *d)
{
	if (idx >= s->nptrs)
	{
		Z_WARNING("share overflow (%i >= %i)", idx, s->nptrs);
		return NULL;
	}

	s->ptrs[idx] = d;
	s->wp[idx] = Z_SHARE_RO;
	return d;
}

int z_share_server_serve(z_share_server *s)
{
	z_size last = s->nptrs;

	while(1)
	{
		z_data req = z_ipc_server_wait(s->srv, NULL, NULL);
		if (req.size == 0)
		{
			z_size idx = z_data_retrieve_query_code(&req);
			z_data res = z_data_init(0, 0);
			if (idx < s->nptrs)
			{
				res = *(s->ptrs[idx]);
				last = idx;
			}
			z_ipc_server_reply(s->srv, &res);
		}
		else
		{
			if (last < s->nptrs && s->wp[last] == Z_SHARE_RW)
			{
				*(s->ptrs[last]) = req;
			}
			z_ipc_server_reply_empty(s->srv);
		}

		sleep(1);
	}

	return 0;
}

z_share_client z_share_client_init(z_ipc_client *ipc)
{
	z_share_client tmp;
	tmp.cli = ipc;
	return tmp;
}

int z_share_client_release(z_share_client c)
{
	return 0;
}

z_data z_share_client_pull(z_share_client *c, z_size idx)
{
	z_data req = z_data_init(0, 0);
	z_data_assign_query_code(&req, idx);
	z_ipc_client_send_request(c->cli, &req);
	z_data res = z_ipc_client_recieve_response(c->cli);
	return res;
}

z_data z_share_client_push(z_share_client *c, z_size idx, z_data *d)
{
	z_data tmp = z_share_client_pull(c, idx);
	z_ipc_client_send_request(c->cli, d);
	z_ipc_client_recieve_response(c->cli);
	return tmp;
}
